package repositories

import (
	"fmt"
	"log"
	"strconv"

	sq "github.com/Masterminds/squirrel"

	"gitee.com/yanxingshuyuan/backend/server/models"
	"github.com/jmoiron/sqlx"
)

type TagRepo struct {
	DB *sqlx.DB
}

func NewTagRepo(db *sqlx.DB) *TagRepo {
	return &TagRepo{
		DB: db,
	}
}

var KindMap = map[string]int{
	"topic":   0,
	"event":   1,
	"people":  2,
	"place":   3,
	"time":    4,
	"emotion": 5,
}

func (r *TagRepo) ListNewsTags(t string) []models.Tag {
	tags := []models.Tag{}
	var kind = KindMap[t]

	r.DB.Select(&tags, "SELECT * from tags where kind = $1", kind)
	log.Printf("selected tags: %v\n", tags)
	return tags
}

func (r *TagRepo) ListTags(cat string, kind string) []models.Tag {
	tags := []models.Tag{}

	// TODO: 改为使用goqu
	psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar)
	q := psql.Select("*").From("tags")

	if cat != "" {
		c, err := strconv.Atoi(cat)
		if err != nil {
			log.Printf("Error converting parameter role %v to int\n", cat)
			return tags
		}
		q = q.Where("cat = ?", c)
	}
	if kind != "" {
		k, err := strconv.Atoi(kind)
		if err != nil {
			log.Printf("Error converting parameter kind %v to int\n", kind)
			return tags
		}
		q = q.Where("kind = ?", k)
	}
	q = q.Where("active = ?", true)

	sql, args, err := q.ToSql()
	log.Printf("Got sql: %v, %#v\n", sql, args)
	if err != nil {
		log.Printf("err building sql for ListTags : %v\n", err)
	}

	err = r.DB.Select(&tags, sql, args...)
	if err != nil {
		log.Printf("error selecting from tags: %v, with error: %v\n", sql, err)
		return tags
	}

	log.Printf("selected tags: %v\n", tags)
	return tags
}

func (r *TagRepo) UpdateTags(tags []models.Tag, mid string, table models.MatTable) bool {
	tx, err := r.DB.Beginx()
	defer tx.Commit()
	if err != nil {
		fmt.Printf("Error creating transaction")
	}
	return r.UpdateTagsForMat(tags, mid, tx, table)
}

func (r *TagRepo) UpdateTagsForMat(tags []models.Tag, mid string, tx *sqlx.Tx, table models.MatTable) bool {
	t := string(table)
	for i := range tags {
		tag := &tags[i]
		fmt.Printf("updating tag: %v:%v\n", tag.ID, tag.Val)
		sql := `INSERT INTO tags (kind, cat, val) VALUES (:kind, :cat, :val)
		 ON CONFLICT ON CONSTRAINT tags_uniq DO UPDATE SET kind = EXCLUDED.kind, cat = EXCLUDED.cat, val = EXCLUDED.val RETURNING id`

		if table == models.MatTableMats {
			sql = `INSERT INTO tags (kind, cat, val, active) VALUES (:kind, :cat, :val, true)
		 ON CONFLICT ON CONSTRAINT tags_uniq DO UPDATE SET kind = EXCLUDED.kind, cat = EXCLUDED.cat, val = EXCLUDED.val, active = true RETURNING id`
		}
		nstmt, err := tx.PrepareNamed(sql)
		if err != nil {
			log.Printf("error preparing statment:%v, with err:%v\n", tag, err)
			return false
		}
		err = nstmt.Get(&tag.ID, tag)
		if err != nil {
			log.Printf("error adding new tag: %#v, with error:%v\n", tag, err)
			return false
		}
		fmt.Printf("inserting mat_tag relation: %v:%v\n", mid, tag.ID)
		_, err = tx.Exec("INSERT INTO "+t+"_tags (mid, tid) VALUES ($1, $2) ON CONFLICT ON CONSTRAINT "+t+"_tags_pk DO NOTHING", mid, tag.ID)
		if err != nil {
			log.Printf("Error upserting %v_tags: %#v, %#v, with error:%v\n", t, mid, tag, err)
			return false
		}
	}
	// 删除数据表中多余的tag（即本次被删除掉的tag）
	var tagids []int
	for i := range tags {
		tagids = append(tagids, tags[i].ID)
	}

	if len(tagids) != 0 {
		query, args, err := sqlx.In("DELETE FROM "+t+"_tags mt where mt.mid = ? and mt.tid not in (?)", mid, tagids)
		if err != nil {
			log.Printf("error making in query from db:[%#v], with err:%v\n", tagids, err)
		}
		query = tx.Rebind(query)
		_, err = tx.Exec(query, args...)
		if err != nil {
			log.Printf("error deleting tags for mid %#v/%v\n", tagids, mid)
		}
	} else {
		_, err := tx.Exec("DELETE FROM "+t+"_tags mt where mt.mid = $1", mid)
		if err != nil {
			log.Printf("error deleting tags for mid %#v\n", mid)
		}
	}

	return true
}
